using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using WPCoco.Helpers;
using Microsoft.Xna.Framework;
using System.IO;

namespace WPCoco.Particles.Codecs
{
    /// <summary>
    /// Coco common format
    /// Plist file that can be creted manually or with Particle Designer
    /// http://particledesigner.71squared.com/
    /// </summary>
    public class CocoPDReader : IParticleSystemReader
    {
        bool CanRead(Dictionary<string, object> data) 
        {
            return (data.ContainsKey("emitterType") &&
                    data.ContainsKey("startParticleSize") &&
                    data.ContainsKey("startParticleSizeVariance") &&
                    data.ContainsKey("duration") &&
                    data.ContainsKey("maxParticles"));
        }

        int GetInteger(Dictionary<string, object> data, string key, int def) 
        {
            if (!data.ContainsKey(key)) return def;
            if (data[key] is Int32) return (Int32)data[key];
            return def;
        }

        float GetFloat(Dictionary<string, object> data, string key, float def)
        {
            if (!data.ContainsKey(key)) return def;
            if (data[key] is Double) return (float)((Double)data[key]);
            return def;
        }

        string GetString(Dictionary<string, object> data, string key, string def)
        {
            if (!data.ContainsKey(key)) return def;
            if (data[key] is String) return data[key] as string;
            return def;
        }

        public ParticleSystem Read(XDocument document)
        {
            Dictionary<string, object> data = PlistHelper.LoadObjectFromDocument(document) as Dictionary<string, object>;
            if (data == null) return null;
            if (!CanRead(data)) return null;
            ParticleSystem s = new ParticleSystem();

            int maxParticles = (int)GetFloat(data, "maxParticles", 0);
            if (maxParticles == 0) return null;
            s.TotalParticles = maxParticles;

            s.ParticleAngle = 360 - GetFloat(data, "angle", 0);
            s.ParticleAngleVariation = GetFloat(data, "angleVariance", 0);

            s.Duration = GetFloat(data, "duration", 0);

            s.IsAdditive = GetFloat(data, "blendAdditive", 0) != 0;
            s.NonPremultiplied = GetFloat(data, "nonPremultipled", 0) != 0;

            //"blendFuncSource", "blendFuncDestination"

            s.StartColor = new Vector4(GetFloat(data, "startColorRed", 0),
                                       GetFloat(data, "startColorGreen", 0),
                                       GetFloat(data, "startColorBlue", 0),
                                       GetFloat(data, "startColorAlpha", 0));

            s.StartColorVariation = new Vector4(GetFloat(data, "startColorVarianceRed", 0),
                                                GetFloat(data, "startColorVarianceGreen", 0),
                                                GetFloat(data, "startColorVarianceBlue", 0),
                                                GetFloat(data, "startColorVarianceAlpha", 0));

            s.EndColor = new Vector4(GetFloat(data, "finishColorRed", 0),
                                     GetFloat(data, "finishColorGreen", 0),
                                     GetFloat(data, "finishColorBlue", 0),
                                     GetFloat(data, "finishColorAlpha", 0));

            s.EndColorVariation = new Vector4(GetFloat(data, "finishColorVarianceRed", 0),
                                              GetFloat(data, "finishColorVarianceGreen", 0),
                                              GetFloat(data, "finishColorVarianceBlue", 0),
                                              GetFloat(data, "finishColorVarianceAlpha", 0));

            s.StartSize = GetFloat(data, "startParticleSize", 0);
            s.StartSizeVariation = GetFloat(data, "startParticleSizeVariance", 0);
            s.EndSize = GetFloat(data, "finishParticleSize", 0);
            s.EndSizeVariation = GetFloat(data, "finishParticleSizeVariance", 0);

            /*
            s.SourcePosition = new Vector2(GetFloat(data, "sourcePositionx", 0),
                                           GetFloat(data, "sourcePositiony", 0));
            */
            s.SourcePosition = Vector2.Zero;

            s.PositionVariance = new Vector2(GetFloat(data, "sourcePositionVariancex", 0),
                                             GetFloat(data, "sourcePositionVariancey", 0));


            s.StartSpin = GetFloat(data, "rotationStart", 0);
            s.StartSpinVariation = GetFloat(data, "rotationStartVariance", 0);
            s.EndSpin = GetFloat(data, "rotationEnd", 0);
            s.EndSpinVariation = GetFloat(data, "rotationEndVariance", 0);

            s.Mode = (ParticleMode)((int)GetFloat(data, "emitterType", 0));



            switch (s.Mode)
            {
                case ParticleMode.Gravity:
                    s.GravitySystemData.Gravity = new Vector2(GetFloat(data, "gravityx", 0),
                                                              -GetFloat(data, "gravityy", 0));
                    s.GravitySystemData.Speed = GetFloat(data, "speed", 0);
                    s.GravitySystemData.SpeedVariation = GetFloat(data, "speedVariance", 0);

                    s.GravitySystemData.RadialAcceleration = GetFloat(data, "radialAcceleration", 0);
                    s.GravitySystemData.RadialAccelerationVariation = GetFloat(data, "radialAccelVariance", 0);

                    s.GravitySystemData.TangencialAcceleration = GetFloat(data, "tangentialAcceleration", 0);
                    s.GravitySystemData.TangencialAccelerationVariation = GetFloat(data, "tangentialAccelVariance", 0);
                    break;
                case ParticleMode.Radial:
                    s.RadialSystemData.StartRadius = GetFloat(data, "maxRadius", 0);
                    s.RadialSystemData.StartRadiusVariation = GetFloat(data, "maxRadiusVariance", 0);
                    s.RadialSystemData.EndRadius = GetFloat(data, "minRadius", 0);
                    s.RadialSystemData.EndRadiusVariation = 0;

                    s.RadialSystemData.RotationPerSecond = GetFloat(data, "rotatePerSecond", 0);
                    s.RadialSystemData.RotationPerSecondVariation = GetFloat(data, "rotatePerSecondVariance", 0);
                    break;
                default:
                    return null;
            }

            s.ParticleLife = GetFloat(data, "particleLifespan", 0);
            s.ParticleLifeVariation = GetFloat(data, "particleLifespanVariance", 0);

            s.EmissionRate = s.TotalParticles / s.ParticleLife;

            string textureFileName = GetString(data, "textureFileName", null);
            if (!string.IsNullOrEmpty(textureFileName))
                s.TextureKey = Path.GetDirectoryName(textureFileName) + "/" + Path.GetFileNameWithoutExtension(textureFileName);

            return s;
        }
    }
}
